/**
 * Copyright 2019 吉鼎科技.

 * <p>
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.apache.org/licenses/LICENSE-2.0
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package cn.easyplatform.web.task.zkex.simple;

import cn.easyplatform.EasyPlatformWithLabelKeyException;
import cn.easyplatform.lang.Nums;
import cn.easyplatform.lang.Streams;
import cn.easyplatform.lang.Strings;
import cn.easyplatform.messages.request.UploadRequestMessage;
import cn.easyplatform.messages.vos.FileVo;
import cn.easyplatform.messages.vos.UploadVo;
import cn.easyplatform.messages.vos.datalist.ListUploadVo;
import cn.easyplatform.messages.vos.executor.EndVo;
import cn.easyplatform.messages.vos.executor.ErrorVo;
import cn.easyplatform.spi.service.ComponentService;
import cn.easyplatform.type.IResponseMessage;
import cn.easyplatform.type.ListRowVo;
import cn.easyplatform.utils.Images;
import cn.easyplatform.web.WebApps;
import cn.easyplatform.web.contexts.Contexts;
import cn.easyplatform.web.dialog.MessageBox;
import cn.easyplatform.web.dialog.ProgressDialog;
import cn.easyplatform.web.ext.ComponentBuilder;
import cn.easyplatform.web.ext.zul.Import;
import cn.easyplatform.web.service.ServiceLocator;
import cn.easyplatform.web.task.OperableHandler;
import cn.easyplatform.web.task.event.EventListenerHandler;
import cn.easyplatform.web.task.zkex.ListSupport;
import cn.easyplatform.web.utils.PageUtils;
import cn.easyplatform.web.utils.WebUtils;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateFormatUtils;
import org.zkoss.util.media.Media;
import org.zkoss.util.resource.Labels;
import org.zkoss.zk.ui.Component;
import org.zkoss.zk.ui.Components;
import org.zkoss.zk.ui.event.Event;
import org.zkoss.zk.ui.event.EventListener;
import org.zkoss.zk.ui.event.Events;
import org.zkoss.zk.ui.event.UploadEvent;
import org.zkoss.zk.ui.util.Clients;
import org.zkoss.zkmax.zul.Dropupload;
import org.zkoss.zul.Button;
import org.zkoss.zul.Toolbarbutton;

import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;


/**
 * @author <a href="mailto:davidchen@epclouds.com">littleDog</a> <br/>
 * @since 2.0.0 <br/>
 */
public class ImportBuilder implements ComponentBuilder,
        EventListener<UploadEvent> {

    private Import imp;

    private OperableHandler mainTaskHandler;

    private ListSupport support;

    private Component anchor;

    /**
     * @param imp
     * @param mainTaskHandler
     */
    public ImportBuilder(OperableHandler mainTaskHandler, Import imp) {
        this.imp = imp;
        this.mainTaskHandler = mainTaskHandler;
    }

    public ImportBuilder(ListSupport support, Import imp, Component anchor) {
        this.support = support;
        this.mainTaskHandler = support.getMainHandler();
        this.imp = imp;
        this.anchor = anchor;
    }

    @Override
    public Component build() {
        // 如果目标不为空
        if (!Strings.isBlank(imp.getTarget())) {
            int index = imp.getTarget().indexOf(":");
            String type = imp.getTarget().substring(0, index);
            if (!type.equals("list") && !type.equals("field"))
                throw new EasyPlatformWithLabelKeyException(
                        "component.property.not.found", "<import>", "target");
        }
        if (imp.getType().equals("drop")) {
            Dropupload upload = new Dropupload();
            upload.setId(imp.getId());
            upload.setHflex(imp.getHflex());
            upload.setVflex(imp.getVflex());
            upload.setVisible(imp.isVisible());
            upload.setStyle(imp.getStyle());
            upload.setTooltiptext(imp.getTooltiptext());
            upload.setTooltip(imp.getTooltip());
            upload.setTop(imp.getTop());
            upload.setLeft(imp.getLeft());
            upload.setMold(imp.getMold());
            upload.setSclass(imp.getSclass());
            upload.setEvent(imp.getEvent());
            upload.setHeight(imp.getHeight());
            upload.setWidth(imp.getWidth());
            upload.setMaxsize(imp.getMaxSize());
            upload.setNative(true);
            upload.setContent(imp.getLabel());
            PageUtils.checkAccess(mainTaskHandler.getAccess(), upload);
            if (!Strings.isBlank(imp.getAnchor()))
                upload.setAnchor(imp.getFellow(imp.getAnchor()));
            //upload.setDetection(imp.getAccept());
            upload.addEventListener(Events.ON_UPLOAD, this);
            Components.replace(imp, upload);
            return upload;
        } else {
            Button button = null;
            if (imp.getType().equals("button"))
                button = imp;
            else if (imp.getType().equals("link")) {
                button = new Toolbarbutton(imp.getLabel());
                button.setId(imp.getId());
                button.setHflex(imp.getHflex());
                button.setVflex(imp.getVflex());
                button.setVisible(imp.isVisible());
                button.setStyle(imp.getStyle());
                button.setTooltiptext(imp.getTooltiptext());
                button.setTooltip(imp.getTooltip());
                button.setTop(imp.getTop());
                button.setLeft(imp.getLeft());
                button.setMold(imp.getMold());
                if (!Strings.isBlank(imp.getDir()))
                    button.setDir(imp.getDir());
                button.setDisabled(imp.isDisabled());
                button.setHoverImage(imp.getHoverImage());
                button.setImage(imp.getImage());
                button.setIconSclass(imp.getIconSclass());
                if (!Strings.isBlank(imp.getOrient()))
                    button.setOrient(imp.getOrient());
                button.setSclass(imp.getSclass());
                button.setEvent(imp.getEvent());
                button.setHeight(imp.getHeight());
                button.setWidth(imp.getWidth());
                button.setAutodisable(imp.getAutodisable());
                Components.replace(imp, button);
            } else
                throw new EasyPlatformWithLabelKeyException(
                        "component.property.not.found", "<import>", "type");
            StringBuilder sb = new StringBuilder();
            sb.append("true,native").append(",maxsize=")
                    .append(imp.getMaxSize()).append(",multiple=")
                    .append(imp.isMultiple());
            if (!Strings.isBlank(imp.getAccept()))
                sb.append(",accept=").append(imp.getAccept());
            button.setUpload(sb.toString());
            PageUtils.checkAccess(mainTaskHandler.getAccess(), button);
            button.addEventListener(Events.ON_UPLOAD, this);
            sb = null;
            return button;
        }
    }

    @Override
    public void onEvent(UploadEvent event) throws Exception {
        if (event.getMedias() == null) {//上传文件过大
            MessageBox.showMessage(Labels.getLabel("message.dialog.title.error"), Labels.getLabel("explorer.upload.max"));
        } else {
            List<FileVo> files = new ArrayList<FileVo>();
            String[] accepts = {};
            if (!Strings.isBlank(imp.getAccept()) && !"none".equals(imp.getAccept())) {
                accepts = imp.getAccept().toLowerCase().split("\\|");
                for (int i = 0; i < accepts.length; i++) {
                    if (!accepts[i].startsWith(".") && accepts[i].indexOf("/") > 0)
                        accepts[i] = StringUtils.substringBefore(accepts[i], "/");
                }
            }
            //处理web前端
            String path = null;
            if (imp.getBackup() != null && !imp.getBackup().startsWith("$707") && !imp.getBackup().startsWith("$729")) {
                path = imp.getBackup();
                if (path.contains("&dt"))
                    path = path.replace("&dt", DateFormatUtils.format(new Date(), "yyyyMMdd"));
            }
            for (Media media : event.getMedias()) {
                if (accepts.length > 0) {
                    boolean isAccepted = false;
                    for (String accept : accepts) {
                        if (!isAccepted) {
                            if (accept.startsWith(".")) {
                                isAccepted = media.getName().toLowerCase().endsWith(accept);
                            } else {
                                isAccepted = media.getContentType().toLowerCase().startsWith(accept);
                            }
                        }
                    }
                    if (!isAccepted) {
                        Clients.wrongValue(event.getTarget(), Labels.getLabel("explorer.file.reject"));
                        return;
                    }
                }
                FileVo fv = null;
                try {
                    fv = new FileVo(media.getName(), media.getByteData());
                } catch (IllegalStateException e) {
                    fv = new FileVo(media.getName(), IOUtils.toByteArray(media.getStreamData()));
                }
                fv.setContentTyp(media.getContentType());
                fv.setFormat(media.getFormat());
                if (path != null) {
                    String filename = fv.getFileName();
                    if (imp.isObfuscation()) {
                        filename = RandomStringUtils.random(32, true, true) + "."
                                + FilenameUtils.getExtension(filename);
                        fv.setFileName(filename);
                    }
                    String dir = WebUtils.getFile(path);
                    File folder = new File(dir);
                    if (!folder.exists())
                        FileUtils.forceMkdir(folder);
                    String file = dir + File.separatorChar + filename;
                    Streams.writeAndClose(new FileOutputStream(file), fv.getData());
                    String[] wh = null;
                    if (imp.getThumbnail0() != null && (wh = StringUtils.split(imp.getThumbnail0(), ",")).length == 2) {
                        int w = Nums.toInt(wh[0], -1);
                        int h = Nums.toInt(wh[1], -1);
                        Images.zoomScale(file, dir + File.separatorChar + "t0_" + filename, w, h, null);
                    }
                    if (imp.getThumbnail1() != null && (wh = StringUtils.split(imp.getThumbnail1(), ",")).length == 2) {
                        int w = Nums.toInt(wh[0], -1);
                        int h = Nums.toInt(wh[1], -1);
                        Images.zoomScale(file, dir + File.separatorChar + "t1_" + filename, w, h, null);
                    }
                    if (imp.getThumbnail2() != null && (wh = StringUtils.split(imp.getThumbnail2(), ",")).length == 2) {
                        int w = Nums.toInt(wh[0], -1);
                        int h = Nums.toInt(wh[1], -1);
                        Images.zoomScale(file, dir + File.separatorChar + "t2_" + filename, w, h, null);
                    }
                    if (imp.getThumbnail3() != null && (wh = StringUtils.split(imp.getThumbnail3(), ",")).length == 2) {
                        int w = Nums.toInt(wh[0], -1);
                        int h = Nums.toInt(wh[1], -1);
                        Images.zoomScale(file, dir + File.separatorChar + "t3_" + filename, w, h, null);
                    }
                    if (imp.getThumbnail4() != null && (wh = StringUtils.split(imp.getThumbnail4(), ",")).length == 2) {
                        int w = Nums.toInt(wh[0], -1);
                        int h = Nums.toInt(wh[1], -1);
                        Images.zoomScale(file, dir + File.separatorChar + "t4_" + filename, w, h, null);
                    }
                    fv.setData(null);
                }
                files.add(fv);
            }
            UploadVo uv = null;
            if (support == null)
                uv = new UploadVo(imp.getTarget(), files);
            else {
                WebUtils.setAnchor(anchor);
                ListRowVo rowVo = WebUtils.getAnchorValue(anchor);
                Object[] data = support.isCustom() ? rowVo.getData() : rowVo
                        .getKeys();
                uv = new ListUploadVo(imp.getTarget(), files, support.getComponent().getId(), data);
            }
            uv.setPath(imp.getPath());
            uv.setLogic(imp.getLogic());
            uv.setBefore(imp.getBefore());
            uv.setAfter(imp.getAfter());
            uv.setFirstColNum(imp.getFirstColNum());
            uv.setFirstRowNum(imp.getFirstRowNum());
            uv.setLastColNum(imp.getLastColNum());
            uv.setLastRowNum(imp.getLastRowNum());
            uv.setCharset(imp.getCharset());
            uv.setCountOfThread(imp.getCountOfThread());
            uv.setProgress(imp.isProgress());
            if (path == null) {
                List<String> thumbnails = new ArrayList<>();
                if (imp.getThumbnail0() != null)
                    thumbnails.add(imp.getThumbnail0());
                if (imp.getThumbnail1() != null)
                    thumbnails.add(imp.getThumbnail1());
                if (imp.getThumbnail2() != null)
                    thumbnails.add(imp.getThumbnail2());
                if (imp.getThumbnail3() != null)
                    thumbnails.add(imp.getThumbnail3());
                if (imp.getThumbnail4() != null)
                    thumbnails.add(imp.getThumbnail4());
                if (!thumbnails.isEmpty()) {
                    uv.setThumbnails(new String[thumbnails.size()]);
                    thumbnails.toArray(uv.getThumbnails());
                }
                thumbnails = null;
                uv.setBackup(imp.getBackup());
            } else {
                uv.setObfuscation(false);
                uv.setBackup(path);
            }
            uv.setFilename(imp.getFilename());
            uv.setSheetNames(imp.getSheetNames());
            uv.setColumnsRow(imp.getColumnsRow());
            uv.setFormat(imp.getFormat());
            if (uv.isProgress()) {
                ProgressDialog mc = new ProgressDialog(imp.getPage());
                EventListener<Event> el = new EventListener<Event>() {
                    @Override
                    public void onEvent(Event event12) throws Exception {
                        Object obj = event12.getData();
                        mc.display(obj);
                        if (obj instanceof EndVo || obj instanceof ErrorVo) {
                            Contexts.unsubscribe(mainTaskHandler.getId(), this);
                            if (obj instanceof EndVo) {
                                if (!Strings.isBlank(imp.getEvent())) {
                                    EventListenerHandler el = new EventListenerHandler(event.getName(), mainTaskHandler,
                                            imp.getEvent(), anchor);
                                    el.onEvent(event);
                                }
                            }
                        }
                    }
                };
                Contexts.subscribe(mainTaskHandler.getId(), el);
                if (!doUpload(uv, null)) {
                    Contexts.unsubscribe(mainTaskHandler.getId(), el);
                    mc.display(new EndVo());
                }
            } else {
                Clients.showBusy(Labels.getLabel("message.long.running", new Object[]{imp.getLabel()}));
                final UploadVo uvo = uv;
                event.getTarget().addEventListener("onLater", new EventListener<Event>() {
                    @Override
                    public void onEvent(Event event1) throws Exception {
                        try {
                            doUpload(uvo, event);
                        } finally {
                            event.getTarget().removeEventListener("onLater", this);
                            Clients.clearBusy();
                        }
                    }
                });
                Events.echoEvent("onLater", event.getTarget(), null);
            }
        }
    }

    private boolean doUpload(UploadVo uv, Event event) throws Exception {
        ComponentService cs = ServiceLocator
                .lookup(ComponentService.class);
        IResponseMessage<?> resp = cs.upload(new UploadRequestMessage(
                mainTaskHandler.getId(), uv));
        if (!resp.isSuccess()) {
            MessageBox.showMessage(resp);
            return false;
        } else if (event != null) {
            if (resp.getBody() != null && !Strings.isBlank(imp.getTarget())) {
                String field = StringUtils.substringAfter(imp.getTarget(), ":");
                Component comp = null;
                if (support == null)
                    comp = mainTaskHandler.getManagedComponents().get(field);
                else if (support instanceof OperableHandler)
                    comp = ((OperableHandler) support).getManagedComponents().get(field);
                if (comp != null)
                    PageUtils.setValue(comp, resp.getBody());
            }
            if (!Strings.isBlank(imp.getEvent())) {
                EventListenerHandler el = new EventListenerHandler(event.getName(), mainTaskHandler,
                        imp.getEvent(), anchor);
                el.onEvent(event);
            }
        }
        return true;
    }
}